`timescale 1ns / 1ps 
module tb();
    reg rst, clk;     


    initial begin            
        $dumpfile("tb.vcd");        
        $dumpvars(0, tb);    
    end

    initial begin
        rst = 1;
        clk = 1;
        forever begin
            #10 clk = ~clk;
        end
    end


    initial begin
        #30
        rst <= 0;
    end

    reg [9:0] dataSeed [0:15];

    initial begin
        dataSeed[0] = 281;
        dataSeed[1] = 271;
        dataSeed[2] = 289;
        dataSeed[3] = 274;
        dataSeed[4] = 281;
        dataSeed[5] = 271;
        dataSeed[6] = 289;
        dataSeed[7] = 274;
        dataSeed[8] = 281;
        dataSeed[9] = 271;
        dataSeed[10] = 289;
        dataSeed[11] = 274;
        dataSeed[12] = 281;
        dataSeed[13] = 271;
        dataSeed[14] = 289;
        dataSeed[15] = 274;
    end

    initial
        #20000 $finish;


    //端口输出的写数据需要用到的信号
    wire [15:0] write_en_port;
    wire [9:0] write_size_port [0:15];
    wire [5:0] write_priority_port [0:15];
    wire [5:0] write_port_port [0:15];
    wire [5:0] write_wait_port [0:15];
    //端口写仲裁结果
    wire [3:0] write_arbitration [0:3];
    wire [7:0] pick_ram [0:3];

    //RAM空闲信号
    wire [31:0] manager_write_ready_group;
    //地址就绪信号
    wire [31:0] address_ready_group;

    //组管理器输出的写需要用到的信号
    wire [3:0] write_en_group;
    wire [9:0] write_size_group [0:3];
    wire [5:0] write_priority_group [0:3];
    wire [5:0] write_port_group [0:3];
    wire [15:0] data_en_group;
    wire [31:0] data_in_group [0:15];

    //RAM入队/出队需要用到的信号
    wire [31:0] enqueue_en_ram;
    wire [5:0] enqueue_priority_ram [0:31];
    wire [9:0] enqueue_value_ram [0:31];
    wire [5:0] enqueue_port_ram [0:31];

    //输出端口需要用到的信号
    wire [15:0] sop_port, eop_port, port_idle_port;
    wire [15:0] enqueue_en_port;
    wire [5:0] enqueue_priority_port [0:15];
    wire [15:0] enqueue_value_port [0:15];

    //端口输出队列用到的信号
    wire [15:0] enqueue_sucess_port_queue;
    wire [31:0] enqueue_update_en;
    wire [7:0] is_first_tail_ram [0:31];
    wire [9:0] enqueue_tail_old_ram [0:31];
    wire [15:0] enqueue_tail_new_ram [0:31];
    wire [15:0] dequeue_vld_port;
    wire [5:0] dequeue_priority_port [0:15];
    wire [7:0] is_last_head_port [0:15];
    wire [15:0] dequeue_head_old_port [0:15];
    wire [31:0] dequeue_vld_ram;
    wire [7:0] is_last_head_ram [0:31];
    wire [9:0] dequeue_head_old_ram [0:31];
    //端口输出队列的更新信号 -- 入队
    wire [15:0] enqueue_update_en_port;
    wire [5:0] enqueue_update_priority_port [0:15];
    wire [7:0] is_first_tail_port [0:15];
    wire [15:0] enqueue_tail_old_port [0:15];
    wire [15:0] enqueue_tail_new_port [0:15];
    //端口输出队列的更新信号 -- 出队
    wire [31:0] dequeue_head_new_en_ram;
    wire [5:0] dequeue_head_new_port_ram [0:31];
    wire [5:0] dequeue_head_new_priority_ram [0:31];
    wire [15:0] dequeue_head_new_value_ram [0:31];
    wire [15:0] dequeue_head_new_en_port;
    wire [5:0] dequeue_head_new_priority_port [0:15];
    wire [15:0] dequeue_head_new_value_port [0:15];



    //数据发生器
    genvar g1, g2, g3, g4;
    generate
        for (g1=0; g1<4; g1=g1+1) begin : genGroup1
            dataGenerator gen(.clk(clk), .rst(rst), .write_arbition(write_arbitration[0][g1]), .memory_pick(pick_ram[0]), .address_ready(address_ready_group[7:0]), .seed(dataSeed[g1]), .data_ready(data_en_group[g1]), .data(data_in_group[g1]), .data_priority(write_priority_port[g1]), .data_target_port(write_port_port[g1]), .data_wait_time(write_wait_port[g1]), .data_write_en(write_en_port[g1]), .data_size(write_size_port[g1]));
        end

        for (g2=0; g2<4; g2=g2+1) begin : genGroup2
            dataGenerator gen(.clk(clk), .rst(rst), .write_arbition(write_arbitration[1][g2]), .memory_pick(pick_ram[1]), .address_ready(address_ready_group[15:8]), .seed(dataSeed[4+g2]), .data_ready(data_en_group[4+g2]), .data(data_in_group[4+g2]), .data_priority(write_priority_port[4+g2]), .data_target_port(write_port_port[4+g2]), .data_wait_time(write_wait_port[4+g2]), .data_write_en(write_en_port[4+g2]), .data_size(write_size_port[4+g2]));
        end

        for (g3=0; g3<4; g3=g3+1) begin : genGroup3
            dataGenerator gen(.clk(clk), .rst(rst), .write_arbition(write_arbitration[2][g3]), .memory_pick(pick_ram[2]), .address_ready(address_ready_group[23:16]), .seed(dataSeed[8+g3]), .data_ready(data_en_group[8+g3]), .data(data_in_group[8+g3]), .data_priority(write_priority_port[8+g3]), .data_target_port(write_port_port[8+g3]), .data_wait_time(write_wait_port[8+g3]), .data_write_en(write_en_port[8+g3]), .data_size(write_size_port[8+g3]));
        end

        for (g4=0; g4<4; g4=g4+1) begin : genGroup4
            dataGenerator gen(.clk(clk), .rst(rst), .write_arbition(write_arbitration[3][g4]), .memory_pick(pick_ram[3]), .address_ready(address_ready_group[31:24]), .seed(dataSeed[12+g4]), .data_ready(data_en_group[12+g4]), .data(data_in_group[12+g4]), .data_priority(write_priority_port[12+g4]), .data_target_port(write_port_port[12+g4]), .data_wait_time(write_wait_port[12+g4]), .data_write_en(write_en_port[12+g4]), .data_size(write_size_port[12+g4]));
        end
    endgenerate

    //组管理器
    genvar gmIndex;
    generate
        for (gmIndex=0; gmIndex<4; gmIndex=gmIndex+1) begin : GroupManager
            groupManager manager(.clk(clk), .rst(rst), .ram_idle_1(manager_write_ready_group[(gmIndex*8)]), .ram_idle_2(manager_write_ready_group[(gmIndex*8)+1]), .ram_idle_3(manager_write_ready_group[(gmIndex*8)+2]), .ram_idle_4(manager_write_ready_group[(gmIndex*8)+3]), .ram_idle_5(manager_write_ready_group[(gmIndex*8)+4]), .ram_idle_6(manager_write_ready_group[(gmIndex*8)+5]), .ram_idle_7(manager_write_ready_group[(gmIndex*8)+6]), .ram_idle_8(manager_write_ready_group[(gmIndex*8)+7]), 
                        .write_en_1(write_en_port[(gmIndex*4)]), .data_priority_1(write_priority_port[(gmIndex*4)]), .data_size_1(write_size_port[(gmIndex*4)]), .data_target_port_1(write_port_port[(gmIndex*4)]), .data_wait_time_1(write_wait_port[(gmIndex*4)]), 
                        .write_en_2(write_en_port[(gmIndex*4)+1]), .data_priority_2(write_priority_port[(gmIndex*4)+1]), .data_size_2(write_size_port[(gmIndex*4)+1]), .data_target_port_2(write_port_port[(gmIndex*4)+1]), .data_wait_time_2(write_wait_port[(gmIndex*4)+1]), 
                        .write_en_3(write_en_port[(gmIndex*4)+2]), .data_priority_3(write_priority_port[(gmIndex*4)+2]), .data_size_3(write_size_port[(gmIndex*4)+2]), .data_target_port_3(write_port_port[(gmIndex*4)+2]), .data_wait_time_3(write_wait_port[(gmIndex*4)+2]), 
                        .write_en_4(write_en_port[(gmIndex*4)+3]), .data_priority_4(write_priority_port[(gmIndex*4)+3]), .data_size_4(write_size_port[(gmIndex*4)+3]), .data_target_port_4(write_port_port[(gmIndex*4)+3]), .data_wait_time_4(write_wait_port[(gmIndex*4)+3]), .write_arbitration(write_arbitration[gmIndex]), .write_en_out(write_en_group[gmIndex]), .write_priority_out(write_priority_group[gmIndex]), .write_size_out(write_size_group[gmIndex]), .write_port_out(write_port_group[gmIndex]), .pick_ram(pick_ram[gmIndex]));
        end
    endgenerate
    
    //空间管理单元
    genvar mmuIndex;
    generate
        for (mmuIndex=0; mmuIndex<32; mmuIndex=mmuIndex+1) begin : MemoryManagerUnit
            memoryManager mmu(.clk(clk), .rst(rst), 
                            .ram_pick(pick_ram[mmuIndex/8][mmuIndex%8]), .write_en(write_en_group[mmuIndex/8]), .write_size(write_size_group[mmuIndex/8]), .write_priority(write_priority_group[mmuIndex/8]), .write_port(write_port_group[mmuIndex/8]), 
                            .data_en_in(data_en_group[mmuIndex/8]), .data_in(data_in_group[mmuIndex/8]), 
                            .queue_update_en(enqueue_update_en[mmuIndex]), .is_first_tail(is_first_tail_ram[mmuIndex]), .queue_tail_old(enqueue_tail_old_ram[mmuIndex]), .queue_tail_new(enqueue_tail_new_ram[mmuIndex]), 
                            .dequeue_en(dequeue_vld_ram[mmuIndex]), .is_last_head(is_last_head_ram[mmuIndex]), .dequeue_head_old(dequeue_head_old_ram[mmuIndex]), .enqueue_sucess(enqueue_sucess_port_queue),
                            .enqueue_en_out(enqueue_en_ram[mmuIndex]), .enqueue_priority_out(enqueue_priority_ram[mmuIndex]), .enqueue_value_out(enqueue_value_ram[mmuIndex]), .enqueue_port_out(enqueue_port_ram[mmuIndex]),
                            .dequeue_head_new_en(dequeue_head_new_en_ram[mmuIndex]), .dequeue_head_new_port(dequeue_head_new_port_ram[mmuIndex]), .dequeue_head_new_priority(dequeue_head_new_priority_ram[mmuIndex]), .dequeue_head_new_value(dequeue_head_new_value_ram[mmuIndex]),
                            .manager_write_ready(manager_write_ready_group[mmuIndex]), .address_ready(address_ready_group[mmuIndex]));
        end
    endgenerate

    //入队交换网络 32 * 16
    ram2PortEnqueueCrossBar enqueueCrossBar(.clk(clk), .rst(rst), 
                                            .enqueue_en_in(enqueue_en_ram), .enqueue_priority_in(enqueue_priority_ram), .enqueue_value_in(enqueue_value_ram), .enqueue_port_in(enqueue_port_ram), .enqueue_sucess(enqueue_sucess_port_queue),
                                            .enqueue_en_out(enqueue_en_port), .enqueue_priority_out(enqueue_priority_port), .enqueue_value_out(enqueue_value_port));

    //入队更新交换网络 16 * 32
    port2RamUpdateCrossBar enqueueUpdateCrossBar(.clk(clk), .rst(rst), 
                                                .enqueue_update_en_port(enqueue_update_en_port), .enqueue_update_priority_port(enqueue_update_priority_port), .is_first_tail_port(is_first_tail_port), .enqueue_tail_old_port(enqueue_tail_old_port), .enqueue_tail_new_port(enqueue_tail_new_port), 
                                                .enqueue_update_en_ram(enqueue_update_en), .is_first_tail_ram(is_last_head_ram), .enqueue_tail_old_ram(enqueue_tail_old_ram), .enqueue_tail_new_ram(enqueue_tail_new_ram));

    //出队交换网络 16 * 32
    port2RamDequeueCrossBar dequeueCrossBar(.clk(clk), .rst(rst), 
                                            .dequeue_vld_port(dequeue_vld_port), .dequeue_priority_port(dequeue_priority_port), .is_last_head_port(is_last_head_port), .dequeue_head_old_port(dequeue_head_old_port), 
                                            .dequeue_vld_ram(dequeue_vld_ram), .is_last_head_ram(is_last_head_ram), .dequeue_head_old_ram(dequeue_head_old_ram));

    //出队更新交换网络 32 * 16
    ram2portUpdateCrossBar dequeueUpdateCrossBar(.clk(clk), .rst(rst), 
                                                .dequeue_head_new_en_in(dequeue_head_new_en_ram), .dequeue_head_new_port_in(dequeue_head_new_port_ram), .dequeue_head_new_priority_in(dequeue_head_new_priority_ram), .dequeue_head_new_value_in(dequeue_head_new_value_ram), 
                                                .dequeue_head_new_en_out(dequeue_head_new_en_port), .dequeue_head_new_priority_out(dequeue_head_new_priority_port), .dequeue_head_new_value_out(dequeue_head_new_value_port));

    //端口输出队列
    genvar portQIndex;
    generate
        for (portQIndex=0; portQIndex<16; portQIndex=portQIndex+1) begin : queueOutQueue
            queueOutSide portQueue(.clk(clk), .rst(rst), 
                                .enqueue_en(enqueue_en_port[portQIndex]), .enqueue_priority(enqueue_priority_port[portQIndex]), .enqueue_value(enqueue_value_port[portQIndex]), .port_out_idle(port_idle_port[portQIndex]), 
                                .dequeue_head_update_en(dequeue_head_new_en_port[portQIndex]), .dequeue_head_priority(dequeue_head_new_priority_port[portQIndex]), .dequeue_head_new(dequeue_head_new_value_port[portQIndex]), 
                                .enqueue_sucess(enqueue_sucess_port_queue[portQIndex]), .enqueue_update_en(enqueue_update_en_port[portQIndex]), .enqueue_update_priority(enqueue_update_priority_port[portQIndex]), .is_first_tail(is_first_tail_port[portQIndex]), .enqueue_tail_old(enqueue_tail_old_port[portQIndex]), .enqueue_tail_new(enqueue_tail_new_port[portQIndex]), 
                                .dequeue_vld(dequeue_vld_port[portQIndex]), .dequeue_priority(dequeue_priority_port[portQIndex]), .is_last_head(is_last_head_port[portQIndex]), .dequeue_head_old(dequeue_head_old_port[portQIndex]));
        end
    endgenerate

    //输出端口
    genvar portIndex;
    generate
        for (portIndex=0; portIndex<16; portIndex=portIndex+1) begin : OutPutPort
            portOut out(.clk(clk), .rst(rst),
                        .date_en(), .data_in(), .port_idle(port_idle_port[portIndex]),
                        .sop(sop_port[portIndex]), .eop(eop_port[portIndex]), .data_out());
        end
    endgenerate
endmodule